home *** CD-ROM | disk | FTP | other *** search
- library KeyHook;
-
- uses
- {$IFDEF Ver80}
- WinProcs,
- WinTypes;
- {$ELSE}
- Windows,
- Messages;
- {$ENDIF}
-
- var
- Hook : HHOOK;
- WM_ToggleIcon,
- WM_TranslateKeys : Cardinal;
- ComposeMode,
- FirstKeyEntered : boolean;
- FirstKey,SecondKey : word;
-
- {$IFDEF Ver80}
- type
- wParam = Word;
- lParam = Longint;
- LResult = Longint;
- {$ENDIF}
-
- function HookProcedure(nCode: Integer; vkCode: WPARAM; MsgInfo: LPARAM) : LRESULT;
- {$IFDEF Ver80} export {$ELSE} stdcall {$ENDIF};
-
- const
- ExcludedKeys = [VK_SHIFT,VK_MENU,VK_CONTROL,VK_LWIN,VK_RWIN,VK_APPS];
-
- var
- KeyState : TKeyboardState;
- Buffer : array[0..2] of char;
- ToASCIIResult : integer;
- begin
- { only act on keystroke if it is being removed from the queue;
- if PeekMessage with PM_NOREMOVE triggered this event, not removing the keystroke, then
- nCode will be HC_NOREMOVE }
- if (nCode = HC_ACTION) then begin
- { by default, don't allow keystroke to be passed to designated window;
- this will be changed if our three Compose checks fail and we call CallNextHookEx }
- Result := 1;
- if (vkCode = VK_CONTROL) and
- ((HiWord(MsgInfo) and KF_UP) <> 0) and { key is being released }
- ((HiWord(MsgInfo) and KF_EXTENDED) <> 0) then begin
- { right control key pressed; switch tray icon to active colour
- and set ComposeMode flag to true, so it will cpature next two keystrokes }
- PostMessage(HWND_BROADCAST,WM_ToggleIcon,1,0);
- ComposeMode := true;
- exit; { bypass CallNextHookEx, since we don't want right control key going to app }
- end
- else if (ComposeMode) and
- ((HiWord(MsgInfo) and KF_UP) = 0) and { key being pressed }
- (not (vkCode in ExcludedKeys)) then begin { key not the shift key }
- if not FirstKeyEntered then begin
- GetKeyboardState(KeyState);
- {$IFDEF Ver80}
- ToASCIIResult := ToASCII(vkCode,MapVirtualKey(vkCode,0),@KeyState,@Buffer,0);
- {$ELSE}
- ToASCIIResult := ToASCII(vkCode,MapVirtualKey(vkCode,0),KeyState,Buffer,0);
- {$ENDIF}
- if ToASCIIResult = 0 then
- FirstKey := 0
- else if ToASCIIResult > 0 then
- FirstKey := ord(Buffer[0])
- else if ToASCIIResult < 0 then begin
- { a dead key has been entered; exit compose
- mode and let Windows take care of composing character itself }
- PostMessage(HWND_BROADCAST,WM_ToggleIcon,0,0);
- ComposeMode := false;
- FirstKeyEntered := false;
- Result := CallNextHookEx(0, nCode, vkCode, MsgInfo);
- exit;
- end;
-
- FirstKeyEntered := true;
- exit; { bypass CallNextHook }
- end
- else begin
- GetKeyboardState(KeyState);
- {$IFDEF Ver80}
- ToASCIIResult := ToASCII(vkCode,MapVirtualKey(vkCode,0),@KeyState,@Buffer,0);
- {$ELSE}
- ToASCIIResult := ToASCII(vkCode,MapVirtualKey(vkCode,0),KeyState,Buffer,0);
- {$ENDIF}
- if ToASCIIResult = 0 then
- SecondKey := 0
- else if ToASCIIResult > 0 then
- SecondKey := ord(Buffer[0])
- else if ToASCIIResult < 0 then begin
- { a dead key has been entered; exit compose
- mode and let Windows take care of composing character itself }
- PostMessage(HWND_BROADCAST,WM_ToggleIcon,0,0);
- ComposeMode := false;
- FirstKeyEntered := false;
- Result := CallNextHookEx(0, nCode, vkCode, MsgInfo);
- exit;
- end;
-
- PostMessage(HWND_BROADCAST,WM_ToggleIcon,0,0);
- ComposeMode := false;
- FirstKeyEntered := false;
- { pass the captured keys and the handle of the window with focus
- (which sent these keys) to calling program, where the keys will
- be translated and the resulting char sent to the GetFocuse window.
- Could do translation here, but it is easier to modify the list
- of characters and their two-key compose seqeunces from the calling program }
- {$IFDEF Ver80}
- PostMessage(HWND_BROADCAST,WM_TranslateKeys,word(FirstKey + (SecondKey shl 8)),GetFocus);
- {$ELSE}
- PostMessage(HWND_BROADCAST,WM_TranslateKeys,MAKELONG(FirstKey,SecondKey),GetFocus);
- {$ENDIF}
- exit; { bypass CallNextHook }
- end;
- end;
- end;
- { make sure this is always called when nCode < 0 (necessary for
- Windows 3.1) }
- Result := CallNextHookEx(0, nCode, vkCode, MsgInfo);
- end;
-
- procedure EnableHook; {$IFDEF Ver80} export {$ELSE} stdcall {$ENDIF};
- begin
- { initialize state flags }
- ComposeMode := false;
- FirstKeyEntered := false;
- {$IFDEF Ver80}
- Hook := SetWindowsHookEx(WH_KEYBOARD, HookProcedure, hInstance, 0);
- {$ELSE}
- Hook := SetWindowsHookEx(WH_KEYBOARD, @HookProcedure, hInstance, 0);
- {$ENDIF}
- end;
-
- procedure DisableHook; {$IFDEF Ver80} export {$ELSE} stdcall {$ENDIF};
- begin
- UnhookWindowsHookEx(Hook);
- end;
-
- exports
- EnableHook,
- DisableHook;
-
- begin
- WM_ToggleIcon := RegisterWindowMessage('DCompose ToggleIcon');
- WM_TranslateKeys := RegisterWindowMessage('DCompose TranslateKeys');
- end.
-